﻿namespace Snoop.Infrastructure.Diagnostics.Providers;

using System.Collections.Generic;
using System.Linq;
using System.Windows;
using Snoop.Data.Tree;

public class FreezeFreezablesDiagnosticProvider : DiagnosticProvider
{
    public override string Name => "Freeze freezables";

    public override string Description => "You should freeze freezable to save memory and increase performance.";

    protected override IEnumerable<DiagnosticItem> GetDiagnosticItemsInternal(TreeItem treeItem)
    {
        if (treeItem.Target is not FrameworkElement frameworkElement)
        {
            return Enumerable.Empty<DiagnosticItem>();
        }

        return this.AnalyzeResourcesRecursive(frameworkElement.Resources, treeItem);
    }

    private IEnumerable<DiagnosticItem> AnalyzeResourcesRecursive(ResourceDictionary dictionary, TreeItem treeItem)
    {
        foreach (var resourceDictionary in dictionary.MergedDictionaries)
        {
            foreach (var item in this.AnalyzeResourcesRecursive(resourceDictionary, treeItem))
            {
                yield return item;
            }
        }

        foreach (var item in this.CheckResources(dictionary, treeItem))
        {
            yield return item;
        }
    }

    private IEnumerable<DiagnosticItem> CheckResources(ResourceDictionary dictionary, TreeItem treeItem)
    {
        foreach (var resourceKey in dictionary.Keys)
        {
            if (resourceKey is null)
            {
                continue;
            }

            if (dictionary.TryGetValue(resourceKey, out var resource)
                && resource is Freezable { IsFrozen: false } freezable)
            {
                yield return
                    new(this,
                        "Freeze freezables",
                        $"Freezing the resource '{resourceKey}' can save memory and increase performance.",
                        DiagnosticArea.Performance,
                        DiagnosticLevel.Info)
                    {
                        TreeItem = treeItem,
                        Dispatcher = freezable.Dispatcher,
                        SourceObject = dictionary
                    };
            }
        }
    }
}